package com.hanserwei.community.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hanserwei.community.entity.po.Owner;
import com.hanserwei.community.entity.po.ParkingCharge;
import com.hanserwei.community.entity.po.ParkingSpace;
import com.hanserwei.community.entity.request.parking.ParkingChargeQueryRequest;
import com.hanserwei.community.entity.request.parking.ParkingChargeSaveRequest;
import com.hanserwei.community.entity.vo.OwnerBriefVO;
import com.hanserwei.community.entity.vo.ParkingChargeVO;
import com.hanserwei.community.enums.ResponseCodeEnum;
import com.hanserwei.community.mapper.ParkingChargeMapper;
import com.hanserwei.community.service.OwnerService;
import com.hanserwei.community.service.ParkingChargeService;
import com.hanserwei.community.service.ParkingSpaceService;
import com.hanserwei.community.uitils.ThrowUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

@Service
@RequiredArgsConstructor
public class ParkingChargeServiceImpl extends ServiceImpl<ParkingChargeMapper, ParkingCharge> implements ParkingChargeService {

    private final OwnerService ownerService;
    private final ParkingSpaceService parkingSpaceService;

    @Override
    public Page<ParkingChargeVO> pageParkingCharges(ParkingChargeQueryRequest request) {
        Page<ParkingCharge> page = new Page<>(request.getCurrent(), request.getPageSize());
        QueryWrapper<ParkingCharge> wrapper = buildQueryWrapper(request);
        Page<ParkingCharge> chargePage = page(page, wrapper);
        List<ParkingChargeVO> voList = convertToVOList(chargePage.getRecords());
        Page<ParkingChargeVO> voPage = new Page<>(chargePage.getCurrent(), chargePage.getSize(), chargePage.getTotal());
        voPage.setRecords(voList);
        return voPage;
    }

    @Override
    public ParkingChargeVO getParkingChargeDetail(Integer id) {
        ThrowUtils.throwIf(id == null || id <= 0, ResponseCodeEnum.INVALID_PARAMETER, "停车费记录ID参数错误！");
        ParkingCharge charge = getById(id);
        ThrowUtils.throwIf(charge == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "停车费记录不存在！");
        List<ParkingChargeVO> list = convertToVOList(Collections.singletonList(charge));
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public boolean createParkingCharge(ParkingChargeSaveRequest request) {
        validateSaveRequest(null, request);
        ParkingCharge charge = new ParkingCharge();
        BeanUtils.copyProperties(request, charge);
        boolean result = save(charge);
        ThrowUtils.throwIf(!result, ResponseCodeEnum.SYSTEM_ERROR, "新增失败！");
        return true;
    }

    @Override
    public boolean updateParkingCharge(Integer id, ParkingChargeSaveRequest request) {
        ThrowUtils.throwIf(id == null || id <= 0, ResponseCodeEnum.INVALID_PARAMETER, "停车费记录ID参数错误！");
        validateSaveRequest(id, request);
        ParkingCharge charge = getById(id);
        ThrowUtils.throwIf(charge == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "停车费记录不存在！");
        BeanUtils.copyProperties(request, charge);
        charge.setId(id);
        boolean result = updateById(charge);
        ThrowUtils.throwIf(!result, ResponseCodeEnum.SYSTEM_ERROR, "更新失败！");
        return true;
    }

    @Override
    public QueryWrapper<ParkingCharge> buildQueryWrapper(ParkingChargeQueryRequest request) {
        QueryWrapper<ParkingCharge> wrapper = new QueryWrapper<>();
        if (request == null) {
            return wrapper;
        }
        wrapper.eq(request.getId() != null && request.getId() > 0, "id", request.getId());
        wrapper.eq(request.getOwnerId() != null && request.getOwnerId() > 0, "owner_id", request.getOwnerId());
        wrapper.eq(request.getParkId() != null && request.getParkId() > 0, "park_id", request.getParkId());
        wrapper.eq(request.getStatus() != null, "status", request.getStatus());
        wrapper.like(StringUtils.hasText(request.getType()), "type", request.getType());
        wrapper.ge(request.getPayDateFrom() != null, "pay_date", request.getPayDateFrom());
        wrapper.le(request.getPayDateTo() != null, "pay_date", request.getPayDateTo());
        if (StringUtils.hasText(request.getParkNumbers())) {
            List<Integer> parkIds = parkingSpaceService.lambdaQuery()
                    .like(ParkingSpace::getNumbers, request.getParkNumbers())
                    .select(ParkingSpace::getId)
                    .list()
                    .stream()
                    .map(ParkingSpace::getId)
                    .distinct()
                    .toList();
            if (parkIds.isEmpty()) {
                wrapper.apply("1 = 0");
            } else {
                wrapper.in("park_id", parkIds);
            }
        }
        wrapper.orderBy(StringUtils.hasText(request.getSortField()), !"descend".equalsIgnoreCase(request.getSortOrder()), request.getSortField());
        return wrapper;
    }

    private void validateSaveRequest(Integer id, ParkingChargeSaveRequest request) {
        ThrowUtils.throwIf(request == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        ThrowUtils.throwIf(request.getOwnerId() == null || request.getOwnerId() <= 0, ResponseCodeEnum.INVALID_PARAMETER, "关联业主不能为空！");
        ThrowUtils.throwIf(request.getParkId() == null || request.getParkId() <= 0, ResponseCodeEnum.INVALID_PARAMETER, "关联车位不能为空！");
        Owner owner = ownerService.getById(request.getOwnerId());
        ThrowUtils.throwIf(owner == null, ResponseCodeEnum.INVALID_PARAMETER, "关联业主不存在！");
        ParkingSpace parkingSpace = parkingSpaceService.getById(request.getParkId());
        ThrowUtils.throwIf(parkingSpace == null, ResponseCodeEnum.INVALID_PARAMETER, "关联车位不存在！");
        BigDecimal money = request.getMoney();
        ThrowUtils.throwIf(money == null || money.signum() < 0, ResponseCodeEnum.INVALID_PARAMETER, "缴费金额不能小于0！");
        LocalDateTime payDate = request.getPayDate();
        ThrowUtils.throwIf(payDate == null, ResponseCodeEnum.INVALID_PARAMETER, "缴费时间不能为空！");
    }

    private List<ParkingChargeVO> convertToVOList(List<ParkingCharge> charges) {
        if (CollectionUtils.isEmpty(charges)) {
            return Collections.emptyList();
        }
        Set<Integer> ownerIds = charges.stream()
                .map(ParkingCharge::getOwnerId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Integer, Owner> ownerMap = ownerIds.isEmpty() ? Collections.emptyMap() : ownerService.listByIds(ownerIds).stream()
                .collect(Collectors.toMap(Owner::getId, owner -> owner));

        Set<Integer> parkIds = charges.stream()
                .map(ParkingCharge::getParkId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Integer, ParkingSpace> parkMap = parkIds.isEmpty() ? Collections.emptyMap() : parkingSpaceService.listByIds(parkIds).stream()
                .collect(Collectors.toMap(ParkingSpace::getId, parkingSpace -> parkingSpace));

        return charges.stream().map(charge -> {
            ParkingChargeVO vo = new ParkingChargeVO();
            BeanUtils.copyProperties(charge, vo);
            vo.setOwnerId(charge.getOwnerId());
            vo.setParkId(charge.getParkId());
            if (charge.getOwnerId() != null) {
                Owner owner = ownerMap.get(charge.getOwnerId());
                if (owner != null) {
                    vo.setOwner(toOwnerBrief(owner));
                }
            }
            if (charge.getParkId() != null) {
                ParkingSpace space = parkMap.get(charge.getParkId());
                if (space != null) {
                    vo.setParkNumbers(space.getNumbers());
                }
            }
            return vo;
        }).toList();
    }

    private OwnerBriefVO toOwnerBrief(Owner owner) {
        if (owner == null) {
            return null;
        }
        return OwnerBriefVO.builder()
                .id(owner.getId())
                .name(owner.getUserName())
                .tel(owner.getTel())
                .houseId(owner.getHouseId())
                .build();
    }
}
